﻿<!DOCTYPE html>
<html>
<head>
<!--
  Copyright (c) 2015-2018 Jean-Marc VIGLINO, 
  released under CeCILL-B (french BSD like) licence: http://www.cecill.info/
-->
  <title>ol-ext: fill pattern</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  
  <meta name="description" content="an OL3 fill style with a set of cartographic patterns to use in your maps." />
  <meta name="keywords" content="ol3, vector, style, fill, pattern, hatch, hatching" />

  <link rel="stylesheet" href="../style.css" />

  <!-- jQuery -->
  <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
  <!-- FontAwesome -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

  <!-- Openlayers -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@latest/ol.css" />
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ol@latest/dist/ol.js"></script>
  <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL,Object.assign"></script>
  
  <!-- ol-ext -->
  <script type="text/javascript" src="../../dist/ol-ext.js"></script>
  <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
  <script src="https://unpkg.com/elm-pep"></script>

  <style>
    #select {
      box-shadow:1px 1px 3px #000;
      background:#fff;
      margin-left:0.5em;
      display:inline-block;
      width:50px;
      height:40px;
    }
    label {
      width:7em;
      text-align:right;
      display: inline-block;
    }
    input[type=number] {
      width:4em;
    }
    #pselect
    {	max-width:300px;
      position: absolute;
      box-shadow:1px 1px 3px #000;
      background:#fff;
    }
    #pselect > div {
      float: left;
      width: 50px;
      height: 40px;
      background-color: #fff;
      border:2px solid #000;
      box-sizing: border-box;
    }
    #pselect > div:hover {
      border-color: red;
    }
  </style>

</head>
<body >
  <a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>

  <a href="../../index.html">
    <h1>ol-ext: fill pattern</h1>
  </a>
  <div class="info">
    <p>
      <i>ol.style.FillPattern</i> set fill pattern style to vector features.
      It defines a set of cartographic patterns to use in your maps.
    </p>
    <p>
      Hatching can be defined with a <i>size </i> for the lines, <i>spacing</i> interval and an <i>angle</i>.
      <br />
      Cross, square, tile, dot and circle patterns can be defines with a <i>size</i> and <i>spacing</i> interval. 
      The <i>angle</i> option is a boolean (0|1) for 45&deg; pattern.
    </p><p>
      You can use font to create a pattern (like FontAwesome patterns in the example <i class="fa fa-smile-o"></i>). NB the font must be loaded before pattern creation.
    </p>
  </div>

  <!-- Map div -->
  <div id="map" style="width:600px; height:400px;"></div>

  <div class="options" style="min-width:300px;">
    <h2>Options:</h2>
    <ul>
      <li>
        Pattern: <div id="select"></div>
        <div id="pselect"></div>
      </li>
      <li style="clear:both;">
        <label>Size:</label>
        <input id="size" type="number" min=0 value=5 onchange="refresh()" />
      </li>
      <li>
        <label>Spacing: </label>
        <input id="spacing" type="number" min=0 value=10 onchange="refresh()" /> 
      </li>
      <li>
        <label>Angle: </label>
        <input id="angle" type="number" value=0 onchange="refresh()" /> <small>(deg)</small>
      </li>
      <li>
        <label>Offset: </label>
        <input id="offset" type="number" value=0 onchange="refresh()" />
      </li>
      <li>
        <label>Scale: </label>
        <input id="scale" type="number" value=1 onchange="refresh()" min=0 step=0.5 />
      </li>
      <li>
        <label>Color: </label>
        <select id="color" onchange="refresh()">
          <option value="blue">blue</option>
          <option value="red">red</option>
          <option value="green">green</option>
          <option value="yellow">yellow</option>
        </select>
      </li>
      <li>
        <label>Background: </label>
        <select id="bg" onchange="refresh()">
          <option value="rgba(255,255,255,0.3)">white</option>
          <option value="rgba(0,0,0,0)">transparent</option>
          <option value="rgba(0,0,255,0.3)">blue</option>
          <option value="rgba(255,0,0,0.3)">red</option>
          <option value="rgba(0,255,0,0.5)">green</option>
          <option value="rgba(255,255,0,0.5)">yellow</option>
        </select>
      </li>
    </ul>
    <!-- force font loading -->
    <i class="fa fa-bug" style="visibility:hidden"></i>
  </div>
  

  <script type="text/javascript">

  var refreh;
  var imgFile = '../data/pattern.png';
  
  $(window).load (function(){
    // AddChar patterns
    ol.style.FillPattern.addPattern ("copy (char pattern)", { char:"©" });
    ol.style.FillPattern.addPattern ("bug (fontawesome)", { char:'\uf188', size:12, font:"10px FontAwesome" });
    ol.style.FillPattern.addPattern ("smiley (width angle)", { char:'\uf118', size:20, angle:true, font:"15px FontAwesome" });

    // Popup
    $("#select").click(function() {
      $("#pselect").toggle();
    });

    var pat = "hatch"
    var spattern = $("#pselect");
    for (var i in ol.style.FillPattern.patterns){
      var p = new ol.style.FillPattern({ pattern:i })
      $("<div>").attr('title',i)
        .css("background-image",'url("'+p.getImage().toDataURL()+'")')
        .click(function(){ pat = $(this).attr("title"); refresh(); })
        .appendTo(spattern);
    }
    var p = new ol.style.FillPattern({ image: new ol.style.Icon({ src : imgFile }) });
    $("<div>").attr('title','Image (PNG)')
        .css("background-image",'url("'+imgFile+'")')
        .click(function(){ pat = $(this).attr("title"); refresh(); })
        .appendTo(spattern);

    // Redraw map
    refresh = function(){
      $("#pselect").hide();
      vector.changed();
      if ( $.inArray(pat,["hatch","cross","dot","circle","square","tile"]) < 0 ) {
        $("#size").prop("disabled",true);
        $("#spacing").prop("disabled",true);
        $("#angle").prop("disabled",true);
        $("#angle").next().text("");
      } else {
        $("#size").prop("disabled",false);
        $("#spacing").prop("disabled",false);
        $("#angle").prop("disabled",false);
        if (pat=="hatch") $("#angle").next().text("(deg)");
        else $("#angle").next().text("(bool)");
      }
      // Calculate image to be drawn outside the map
      var p = new ol.style.FillPattern({
        pattern: pat,
        image: (pat=='Image (PNG)') ? new ol.style.Icon({ src : imgFile }) : undefined,
        ratio: 2,
        color: "#000",
        size: Number($("#size").val()),
        spacing: Number($("#spacing").val()),
        angle: Number($("#angle").val())
      });
      $("#select").css('background-image', 'url('+p.getImage().toDataURL()+')');
    };

    // Layers
    var layer = new ol.layer.Geoportail({ layer: 'ORTHOIMAGERY.ORTHOPHOTOS' });

    /* fix offset ?!
    var offset;
    layer.on('precompose', function(e)
    {	offset=[e.frameState.coordinateToPixelMatrix[12],e.frameState.coordinateToPixelMatrix[12]];
    });
    */

    // The map
    var map = new ol.Map({
      target: 'map',
      view: new ol.View({
        zoom: 5,
        center: [166326, 5992663]
      }),
      layers: [layer]
    });

    function getStyle(feature){
      var p = pat;
      return [ new ol.style.Style({
        fill: new ol.style.FillPattern({
          pattern: (p!='Image (PNG)') ? p : undefined,
          image: (p=='Image (PNG)') ? new ol.style.Icon({ src : imgFile }) : undefined,
          ratio: 1,
          icon: p=='Image (PNG)' ? new ol.style.Icon ({src:'data/target.png'}) : undefined,
          color: $("#color").val(),
          offset: Number($("#offset").val()),
          scale: Number($("#scale").val()),
          fill: new ol.style.Fill ({ color:$("#bg").val() }),
          size: Number($("#size").val()),
          spacing: Number($("#spacing").val()),
          angle: Number($("#angle").val())
        })
      })];
    }

    // Nouvelle source de donnee
    var vector = new ol.layer.Vector({
      source: new ol.source.Vector(),
      style: getStyle
    })
    map.addLayer(vector);
    vector.getSource().addFeature(new ol.Feature(new ol.geom.Polygon([[[259274, 6398696], [63595, 5958419], [635956, 5772524], [259274, 6398696]]])));

    // global so we can remove it later
    var interaction = new ol.interaction.Draw({
      type: 'Polygon',
      source: vector.getSource()
    });
    map.addInteraction(interaction); 

    refresh();
  });
  </script>

</body>
</html>